<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        em,i{font-style: normal;}
        .box{width:200px;margin:50px auto;height:30px;line-height:30px;text-indent:2px;}
        .box span{border: solid 1px black;display: block;}
        .box .list{margin:0;padding:0;list-style: none;border: solid 1px black;border-top:none;text-indent:6px;display:none;}
        .box .list li.active{background-color: #66f;color:#fff;}
        .box .list li{background-size: 20px 20px;background-repeat: no-repeat;background-position: right center;}

    </style>
</head>
<body>
    <select>
        <option>html</option>
        <option>css</option>
        <option>javascript</option>
        <option>nodejs</option>
        <option>mongodb</option>
    </select>

    <div class="box">
        <span>
            <em>显示区域</em>
            <i></i>
        </span>
        <ul class="list">
            <li>html</li>
            <li>css</li>
            <li>javascript</li>
            <li>nodejs</li>
            <li>mongodb</li>
        </ul>
    </div>
</body>
<script>
    // 是否能够观察到每一个细节

    // 1. 获取元素
    var span = document.querySelector(".box span");
    var spanEm = document.querySelector(".box span em");
    var list = document.querySelector(".box .list");
    var lis = document.querySelectorAll(".box .list li");

    // 8. 设置默认选中的项
    var index = 0;
    spanEm.innerHTML = lis[index].innerHTML;
    lis[index].style.backgroundImage = "url(./right.png)";

    // 2. 设置下拉菜单的显示状态开关
    var flag = 0;

    // 鼠标控制

    // 3. 点击显示区域
    span.onclick = function(eve){
        // 4. 取消事件冒泡
        var e = eve || window.event;
        e.stopPropagation();
        // 5. 根据状态，决定显示，或隐藏
        if(flag === 0){
            list.style.display = "block";
            flag = 1;
            // 24. 每次显示下拉菜单，都应该初始化样式和高亮索引
            if(keyIndex !== undefined){
                // 为了避免报错，提前判断keyIndex是否是初始值
                lis[keyIndex].className = "";
                keyIndex = undefined;
            }
            // 28. 初始化时不需要初始化index
            // 因为index永远都是作为上一个索引存在，被清除对应样式
            // index = 0;
        }else{
            list.style.display = "none";
            flag = 0;
        }
    }
    
    // 6. 点击空白隐藏，记得同步状态
    document.onclick = function(){
        list.style.display = "none";
        flag = 0;
    }

    // 7. 绑定鼠标进入离开点击事件
    for(var i=0;i<lis.length;i++){
        lis[i].index = i;
        // 进入，添加高亮样式
        lis[i].onmouseover = function(){
            if(keyIndex !== undefined){
                lis[keyIndex].className = "";
            }
            this.className = "active";
            // 25. 将鼠标进入的元素索引设置给键盘的索引
            keyIndex = this.index;
        }
        // 可离开，取消高亮样式
        lis[i].onmouseout = function(){
            this.className = "";
        }
        // 点击，设置选中的项
        lis[i].onclick = function(){
            // 设置文字到显示区域
            spanEm.innerHTML = this.innerHTML;
            // 9. 设置选中的项
            lis[index].style.backgroundImage = "";
            this.style.backgroundImage = "url(./right.png)";
            // 10. 将本次点击的索引，设置为下次要取消的索引
            index = this.index;
        }
    }

    // 26. 给整个下拉菜单添加离开事件，取消键盘索引对应元素的高亮
    list.onmouseout = function(){
        if(keyIndex !== undefined){
            lis[keyIndex].className = "";
            keyIndex = undefined;
        }
    }

    // 键盘控制

    // 11. 设置键盘对应的默认索引
    var keyIndex = undefined;
    // 绑定键盘事件
    document.onkeydown = function(eve){
        // 27. 下拉菜单不显示，不执行
        if(flag === 0) return;

        var e = eve || window.event;
        var code = e.keyCode || e.which;
        // 上键
        if(code === 38){
            // 12. 判断键盘对应的索引是否是初始值（是否是第一次按下键盘）
            if(keyIndex === undefined){
                // 13. 第一次按下键盘，设置初始索引
                keyIndex = lis.length-1;
                // 14. 根据索引设置样式
                lis[keyIndex].className = "active";
            }else
            // 15. 再判断键盘对应的索引是否到最小值
            if(keyIndex !== 0){
                // 不是最小值
                // 16. 取消改变索引之前引对应元素的样式
                lis[keyIndex].className = "";
                // 17. 改变索引
                keyIndex--;
                // 18. 添加改变索引之后对应元素的样式
                lis[keyIndex].className = "active";
            }
        }
        // 下
        if(code === 40){
            if(keyIndex === undefined){
                keyIndex = 0;
                lis[keyIndex].className = "active";
            }else if(keyIndex !== lis.length-1){
                lis[keyIndex].className = "";
                keyIndex++;
                lis[keyIndex].className = "active";
            }
        }
        // 回车键
        if(code === 13){
            // 19. 回车之后，将当前键盘索引对应的选中内容设置到显示区域
            spanEm.innerHTML = lis[keyIndex].innerHTML;
            // 20. 取消之前的选中项
            lis[index].style.backgroundImage = "";
            // 21. 给本次键盘对应索引的元素添加选中项
            lis[keyIndex].style.backgroundImage = "url(./right.png)";
            // 22. 将本次键盘对应索引设置给默认索引
            // （本次索引，是下一次要取消的索引）
            index = keyIndex;
            // 23. 隐藏下拉菜单，同步状态
            list.style.display = "none";
            flag = 0;
        }
    }
</script>
</html>